Wizard's Crown Numeric Keypad Patch 
v1.0
By Mark Lemmert /aka Nox Ffred
6502 Workshop, LLC
mark@6502workshop.com
====================================


--PATCH BENIFITS--

The original movement key assignments used by Wizard's crown were clumsy for the player. There are good reasons, in my opinion, why those assignments were made by the developers, but the inclusion of a numeric keypad in later Apple II models and the advent of emulators make those reasons no longer relevant. 


This patch changes the movement key assignment to feel more natural to the player on a numeric keypad, which are as follows:

 
7 8 5
4   6
1 2 3



--HOW TO USE PATCH--


To use the patch, simply play the game using the disk images provided. Like normal, boot WCGAME1.DSK, press a key to play the game, insert WCDISK1_PATCH.DSK and WCDISK2_PATCH.DSK when prompted. 

Note: the patch itself was applied to WC_PLAYER_MASTER_DISK1_PATCH.DSK and WC_PLAYER_MASTER_DISK2_PATCH.DSK, so if you create new players disks using the main menu, the disks created will not contain the patch code. I recommend treating the WC_PLAYER_MASTER_DISK1_PATCH.DSK and WC_PLAYER_MASTER_DISK2_PATCH.DSK disk images you downloaded as 'masters'. Simply make a copy of those files (on your Windows or MacOS computer) when starting a new game and play using the copies.

 
--WHY IS KEY 5 USED FOR NORTHEAST?====

See "WHATS UP WTH KEY 5" section below



--BACKGROUND--


The Apple II did not have a numeric keypad build into the keyboard until the Apple IIgs was released in 1986. The Apple IIe Platinum had a numeric keyboard but that wasn't released until 1987.

Wizard's Crown was released by Strategic Simulations in 1985.

While an external numeric keypad existed at that time, most users did not have one. This product was likely targeted at businesses buying computers to run accounting software. Accordingly, the developers of Wizard's Crown did not appear to optimize the movement key assignments for intuitive use on a numeric keypad. 


The original Wizard's Crown movement keys were as follows: 

8 1 2
7   3
6 5 4

Obviously, this was not intuitive on a numeric keypad. There was logic to it on the regular keyboard, because 1 is north and then number keys wraps around the compass in sequence, counter clockwise. But, in practice, as player, I found those keys very clumsy to use on the regular keyboard as well. 


My best educated guess as to why the developers chose those original movement key assignments is because: 

a) most people didn't have the external numeric keypad.

b) The ASCII values for the number keys are adjacent. 


These keys are not assigned and I think could have been used for movement keys:

I O  P 
K L  ;
, .  /


However, the ASCII values of those keys aren't numerically adjacent so the code would have ended up with a pile of CMP/CPY/CPX opcodes to parse the keypress, taking up more memory.

Instead, the code uses a lookup table in conjunction with parsing the movement key and handing control off to the movement subroutine, which takes less memory than the alternative. Ultimately we're talking about a handful of bytes but when developing an 8-bit RPG, loosing a handful of bytes could mean having to exclude an important feature or piece of content from the game. 


--WHATS UP WTH KEY 5--

The short answer is that the patch as-is, a 90% improvement, took a few hours to do. Changing key 5 to key 9 would be an order of magnitude, or greater, more difficult if it is even possible, which is unknown. 


The long answer. When Wizard's Crown parses the keypress, it strips the high-order nibble off the ASCII value of the keypress. So, the keypress ASCII value is $B1, $B2, $B3 etc (Apple II uses hi-ascii values), and stripping off the high order nibble gives us a value like 1, 2, 3 etc. That value is used as the index to a lookup table which, I think, contains a code used by the movement subroutine. The new key assignments were achieved by rearranging the order of the values in that lookup table. 

The problem with key 9 is that if it's used as an index to that lookup table, that results in an out-of-bounds lookup because there are only 8 bytes reserved for the table. When working in machine language, there are no safety nets. There is no compiler to warn you "hey, that lookup is out-of-bounds"....the lookup will proceed and the computer will use whatever whatever value happens to be in the memory address after the end of the table that is associated with the index used. Recall "Identify Bishop #9" in Wizardry. This bug was the result of an out-of-bound table lookup. Wizardy was written in Pascal but Robert Woodhead said that he turned off the out-of-bounds lookup protection for various reasons. Note: most out-of-bound lookups crash the game, Bishop #9 turning into a useful player exploit is a much less common outcome. 


The bigger problem is that there is no available memory after the end of the lookup table, so if I "added" a 9th byte to the table, that value would clobber a different value that was important to the game for something. This impact of this is entirely unpredictable without massive investigation. Adding a 9th byte to the table on disk, the source of the table in memory, could also throw off offset values used for the game's RWTS as it's not using a filesystem. It runs right on the metal. 

Another option would be to insert some code along the lines of "If keypress = 9, then set index = 5", so that the 5th byte in the table could be used to store the value for northeast but allow the user to trigger it when pressing the 9 key. The problem with this approach is it would take a few bytes of additional memory in the keypress parser routine and there isn't any available. The only options I can think of would be to find some way to optimize code further in the keyboard parser routine (not a quick thing and no guarantee that bytes can be freed up) or insert a JSR (call subroutine opcode) into the keypress parser and shift the existing parsing code into some other region of memory. Then, the lookup table could be expanded to 9 bytes. But, mapping out the memory usage of the entire game would take a lot of time and there is no guarantee that an empty memory region of sufficient size exists. 
 



--TECHNICAL NOTES--

See Technical Notes folder.




